﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Tetriphone
{
    struct GAMESTATS
{
 public uint[]	specials_spawned;
 public uint[]	specials_collected;
 public uint[]	specials_used;
 public uint[]	specials_rcvd;
 public uint[]	Blocks;
 public uint[]	BFreq;
 public uint[]	SFreq;
 public uint	SecondsPlayed;
 public uint	NumberTetris;
 public uint	NumberLines;
 public uint	NumberBlocks;
 float		bpm;
 public uint	LinesAdded;
 public uint	Won;
 public uint	GamesPlayed;
};

    struct GAMEDATA
{
 public int InitialHeight;
 public int StartLevel;
 public int LinesForLevel;
 public int LevelAmount;
 public int LinesForSpecial;
 public int SpecialMult; 
 public int SpecialCap;
 public int AverageLevel;
 public int Classic;
 public int Delay;
 public uint[] BFreq;
 public uint[] SFreq;
};

    struct WINLISTENTRY		    
{
 public string name;
 public uint points;
};

    public class TetrisLogic
    {
        byte[][][] BLong = new byte[][][]{
    new byte[][]{
        new byte[]{1,0,0,0},
        new byte[]{1,0,0,0},
        new byte[]{1,0,0,0},
        new byte[]{1,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,0,0,0},
        new byte[]{1,1,1,1},
        new byte[]{0,0,0,0}
    },
    new byte[][]{
        new byte[]{1,0,0,0},
        new byte[]{1,0,0,0},
        new byte[]{1,0,0,0},
        new byte[]{1,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,0,0,0},
        new byte[]{1,1,1,1},
        new byte[]{0,0,0,0}
    }
};

        byte[][][] BQuad = new byte[][][]{
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{2,2,0,0},
        new byte[]{2,2,0,0},
        new byte[]{0,0,0,0}
    },
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{2,2,0,0},
        new byte[]{2,2,0,0},
        new byte[]{0,0,0,0}
    },
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{2,2,0,0},
        new byte[]{2,2,0,0},
        new byte[]{0,0,0,0}
    },
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{2,2,0,0},
        new byte[]{2,2,0,0},
        new byte[]{0,0,0,0}
    }
};

        byte[][][] BLeft = new byte[][][]{
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,0,3,0},
        new byte[]{3,3,3,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{3,0,0,0},
        new byte[]{3,0,0,0},
        new byte[]{3,3,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{3,3,3,0},
        new byte[]{3,0,0,0},
        new byte[]{0,0,0,0}
    },new byte[][] {
        new byte[]{0,0,0,0},
        new byte[]{3,3,0,0},
        new byte[]{0,3,0,0},
        new byte[]{0,3,0,0}
    }
};


        byte[][][] BRight = new byte[][][]{
   new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{4,4,4,0},
        new byte[]{0,0,4,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,4,0,0},
        new byte[]{0,4,0,0},
        new byte[]{4,4,0,0}
    },new byte[][] {
        new byte[]{0,0,0,0},
        new byte[]{4,0,0,0},
        new byte[]{4,4,4,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{4,4,0,0},
        new byte[]{4,0,0,0},
        new byte[]{4,0,0,0}
    }
};


        byte[][][] BRed = new byte[][][]{
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{1,1,0,0},
        new byte[]{0,1,1,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,1,0,0},
        new byte[]{1,1,0,0},
        new byte[]{1,0,0,0}
    },
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{1,1,0,0},
        new byte[]{0,1,1,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,1,0,0},
        new byte[]{1,1,0,0},
        new byte[]{1,0,0,0}
    }
};


        byte[][][] BBlue = new byte[][][]{
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,5,5,0},
        new byte[]{5,5,0,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{5,0,0,0},
        new byte[]{5,5,0,0},
        new byte[]{0,5,0,0}
    },
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,5,5,0},
        new byte[]{5,5,0,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{5,0,0,0},
        new byte[]{5,5,0,0},
        new byte[]{0,5,0,0}
    }
};

        byte[][][] BT = new byte[][][]{
    new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{2,2,2,0},
        new byte[]{0,2,0,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,2,0,0},
        new byte[]{2,2,0,0},
        new byte[]{0,2,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{0,2,0,0},
        new byte[]{2,2,2,0},
        new byte[]{0,0,0,0}
    }, new byte[][]{
        new byte[]{0,0,0,0},
        new byte[]{2,0,0,0},
        new byte[]{2,2,0,0},
        new byte[]{2,0,0,0}
    }
};
        const int SPECIAL_BUFFER_LENGTH = 18;
        const int MAX_WINLIST_ENTRIES =	10;
        public const int FIELDWIDTH  		=12;
        public const int FIELDHEIGHT 		=22;
        const int PROT_TETRINET	=	0;
        const int PROT_TETRIFAST	=	1;
        const int PROT_TSPEC	=	2;
        const int PROT_PLAYREC = 3;

        WINLISTENTRY[] Winlist = new WINLISTENTRY[MAX_WINLIST_ENTRIES];

        string NickName="Guest";
        string TeamName="";
        public static byte  MyPosition=1;
        public static string[]  PlayerNames;
        string[]  PlayerTeams;
        int[]   PlayerLevels;
        bool[]  PlayerPlaying;
        string[]  Speclist;
        byte[] SpecialBuffer = new byte[SPECIAL_BUFFER_LENGTH+1];
        public static char[] BlockValue = "012345acnrsbgqo".ToCharArray();

        const byte MaxPlayers = 6;
        long SecondsPlayed = 0;
        int DroppedBlocks = 0;
        bool paused = false;
        int ActiveLevel = 0;
        int BCurrent = -1, BNext = -1;
        byte		   KeyDownPressed=0;
        short BCurrentPosX = 0;
        short BCurrentPosY = 0;
        int BlockOrientation;
        int NextBlockOrientation;
        byte NumberPlayersStart = 0;
        byte NumberPlayersEnd = 0;
        GAMEDATA GameData = new GAMEDATA();
        GAMESTATS CurrentGame = new GAMESTATS();
        byte protocol;

        byte[][] FIELD;
        public static byte[][][] PlayingFields = new byte[MaxPlayers][][];
        byte[][] OwnField;
        public static byte[][] LastFieldBuffer;

        uint	   SpecialsAdded=0;
        int TotalLines = 0;
        int     EventNumber=0;      /* used for numbering in event window */
        char[]    GMSGFirstLine=new char[100];
        char[]    GMSGSecondLine=new char[100];
        char[] GMSGThirdLine = new char[100];

        Random _rand;

        public TetrisLogic()
        {
            FIELD = CreateField();
            PlayingFields = CreatePlayingFields();
            OwnField = CreateField();
            LastFieldBuffer = CreateField();
        }

        byte[][] CreateField()
        {
            byte[][] field = new byte[FIELDWIDTH][];
            for(int i=0;i<FIELDWIDTH;i++)
            {
                field[i] = new byte[FIELDHEIGHT];
            }

            return field;
        }

        byte[][][] CreatePlayingFields()
        {
            byte[][][] playingFields = new byte[MaxPlayers][][];

            for (int i = 0; i < MaxPlayers; i++)
            {
                playingFields[i] = CreateField();
            }

            return playingFields;
        }

        void SetBlock()
        {
            int x, y;
            byte[][] block = null;

            /* Make block permanent at this position */
            if (BCurrent == 0) block = BLong[BlockOrientation];
            if (BCurrent == 1) block= BQuad[BlockOrientation];
            if (BCurrent == 2) block= BLeft[BlockOrientation];
            if (BCurrent == 3) block= BRight[BlockOrientation];
            if (BCurrent == 4) block= BBlue[BlockOrientation];
            if (BCurrent == 5) block= BRed[BlockOrientation];
            if (BCurrent == 6) block= BT[BlockOrientation];

            for (y = 0; y < 4; y++)
                for (x = 0; x < 4; x++)
                {
                    if (block[x][y] != 0)
                        PlayingFields[MyPosition - 1][BCurrentPosX + x][BCurrentPosY + y] = block[x][y];
                }
        }

        bool IsOutOfField(int XPos, int YPos)
        {
            int x, y;
            byte[][] block = null;

            if (BCurrent == 0) block = BLong[BlockOrientation];
            if (BCurrent == 1) block = BQuad[BlockOrientation];
            if (BCurrent == 2) block = BLeft[BlockOrientation];
            if (BCurrent == 3) block = BRight[BlockOrientation];
            if (BCurrent == 4) block = BBlue[BlockOrientation];
            if (BCurrent == 5) block = BRed[BlockOrientation];
            if (BCurrent == 6) block = BT[BlockOrientation];

            for (y = 0; y < 4; y++)
                for (x = 0; x < 4; x++)
                {
                    if (block[x][y] != 0 && (x + XPos < 0 || x + XPos >= FIELDWIDTH || y + YPos < 0 || y + YPos >= FIELDHEIGHT)) return true;
                }

            return false;
        }

        bool IsObstructed(int XPos, int YPos)
        {
            int x, y;
            byte[][] block = null;

            if (BCurrent == 0) block = BLong[BlockOrientation];
            if (BCurrent == 1) block = BQuad[BlockOrientation];
            if (BCurrent == 2) block = BLeft[BlockOrientation];
            if (BCurrent == 3) block = BRight[BlockOrientation];
            if (BCurrent == 4) block = BBlue[BlockOrientation];
            if (BCurrent == 5) block = BRed[BlockOrientation];
            if (BCurrent == 6) block = BT[BlockOrientation];

            for (y = 0; y < 4; y++)
                for (x = 0; x < 4; x++)
                {
                    if (x + XPos >= FIELDWIDTH || y + YPos >= FIELDHEIGHT || x + XPos < 0 || y + YPos < 0) continue;
                    if (block[x][y] != 0 && PlayingFields[MyPosition - 1][x + XPos][y + YPos] != 0) return true;
                }

            return false;
        }

        void FillFieldRandom(int index)
        {
            int i, j;

            _rand = new Random((int)DateTime.Now.Ticks);

            for (i = 0; i < FIELDHEIGHT; i++)
                for (j = 0; j < FIELDWIDTH; j++) PlayingFields[index][j][i] = (byte)(1 + _rand.Next() % 5);
        }

        void ShiftDownField(byte Line)
        {
            int x, y;

            if (Line == 0) return;

            for (y = Line; y > 0; y--)
                for (x = 0; x < FIELDWIDTH; x++) PlayingFields[MyPosition - 1][x][y] = PlayingFields[MyPosition - 1][x][y - 1];

            /* zero out top line */
            for (x = 0; x < FIELDWIDTH; x++) PlayingFields[MyPosition - 1][x][0] = 0;
        }
        
        void AddLineClassic()
        {
             int	x, y;
             char[]	Buffer = new char[100];
 
             /* already dead or only spectating? Don't add line. */
             if (!PlayerPlaying[MyPosition-1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;
 
 
             /* top line filled? */
             for (x = 0; x < FIELDWIDTH; x++) if (PlayingFields[MyPosition-1][x][0] != 0)
             {
              /* dead with this line added */
              BCurrent = -1;
              SecondsPlayed = (long)DateTime.Now.Ticks - SecondsPlayed;
              if (0!=SecondsPlayed) SecondsPlayed++;
              FillFieldRandom(MyPosition-1);
              netcode.Instance.SendField(MyPosition - 1);
              PlayerPlaying[MyPosition-1] = false;
              Buffer = string.Format("playerlost {0}", MyPosition).ToCharArray();
              netcode.Instance.SendSocket(Buffer);
   
              Ui.DrawFields((byte)(MyPosition-1));
              Ui.DrawNextBlock();
  
              return;
             }
 
             /* shift field */
             for (y = 0; y < FIELDHEIGHT - 1; y++)
              for (x = 0; x < FIELDWIDTH; x++) PlayingFields[MyPosition-1][x][y] = PlayingFields[MyPosition-1][x][y+1];
  
             /* (totally) fill line */ 
             for (x = 0; x < FIELDWIDTH; x++) PlayingFields[MyPosition-1][x][FIELDHEIGHT-1] = (byte)(1 + _rand.Next() % 5);
             /* create one space */
             PlayingFields[MyPosition-1][_rand.Next() % FIELDWIDTH][FIELDHEIGHT-1] = 0;
 
             /* if crashed into shifted field... move one line up */
             if (IsObstructed(BCurrentPosX, BCurrentPosY))
             {
 	            BCurrentPosY--;
                KillDoubleDropTimer();
             }
             if (BCurrentPosY < 0) BCurrentPosY = 0;
        }

        private void KillDoubleDropTimer()
        {

        }

        void AddLine()
{
 int	x, y;
 char[] Buffer = new char[100];
 
 /* already dead or only spectating? Don't add line. */
 if (!PlayerPlaying[MyPosition-1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;
 
 CurrentGame.specials_rcvd[0]++;
 
 /* top line filled? */
 for (x = 0; x < FIELDWIDTH; x++) if (PlayingFields[MyPosition-1][x][0] != 0)
 {
  /* dead with this line added */
  BCurrent = -1;
  SecondsPlayed = (long)DateTime.Now.Ticks - SecondsPlayed;
  if (0!=SecondsPlayed) SecondsPlayed++;
  FillFieldRandom(MyPosition-1);
  netcode.Instance.SendField(MyPosition - 1);
  PlayerPlaying[MyPosition-1] = false;
  Buffer = string.Format("playerlost {0}", MyPosition).ToCharArray();
  netcode.Instance.SendSocket(Buffer);
  
  Ui.DrawFields((byte)(MyPosition-1));
  Ui.DrawNextBlock();
  
  return;
 }
 
 /* shift field */
 for (y = 0; y < FIELDHEIGHT - 1; y++)
  for (x = 0; x < FIELDWIDTH; x++) PlayingFields[MyPosition-1][x][y] = PlayingFields[MyPosition-1][x][y+1];
 
 /* Fill line, random spaces are possible */ 
 for (x = 0; x < FIELDWIDTH; x++) PlayingFields[MyPosition-1][x][FIELDHEIGHT-1] = (byte)(_rand.Next() % 6);
 /* at least one space is required */
 PlayingFields[MyPosition-1][_rand.Next() % FIELDWIDTH][FIELDHEIGHT-1] = 0;
 
 
 if (IsObstructed(BCurrentPosX, BCurrentPosY))
 {
 	BCurrentPosY--;
 	KillDoubleDropTimer();
 }
 if (BCurrentPosY < 0) BCurrentPosY = 0;
}
        void ClearLine()
        {
            
            if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;

            CurrentGame.specials_rcvd[1]++;

           
            ShiftDownField(FIELDHEIGHT - 1);
        }
        
        void NukeField()
        {
          
            if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;

            CurrentGame.specials_rcvd[2]++;
            PlayingFields[MyPosition - 1] = CreateField();
        }

        void ClearSpecials()
        {
            int x, y;

            
            if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;

            CurrentGame.specials_rcvd[5]++;

            for (y = 0; y < FIELDHEIGHT; y++)
                for (x = 0; x < FIELDWIDTH; x++)
                    if (PlayingFields[MyPosition - 1][x][y] > 5) PlayingFields[MyPosition - 1][x][y] = (byte)(1 + _rand.Next() % 5);
        }

        void ClearRandom()
        {
            int i;

           
            if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;

            CurrentGame.specials_rcvd[3]++;

            for (i = 0; i < 10; i++) PlayingFields[MyPosition - 1][_rand.Next() % FIELDWIDTH][_rand.Next() % FIELDHEIGHT] = 0;
        }




        void SwitchField(int num)
        {
            int x, y, i = -1;

            
            if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;

            CurrentGame.specials_rcvd[4]++;
            PlayingFields[MyPosition - 1] = PlayingFields[num - 1];

            
            for (y = 5; y >= 0; y--)
                for (x = 0; x < FIELDWIDTH; x++) if (PlayingFields[MyPosition - 1][x][y] != 0) i = y;

            
            if (i == -1) return;

           
            for (x = 6; x > i; x--) ShiftDownField(FIELDHEIGHT - 1);

            while (IsObstructed(BCurrentPosX, BCurrentPosY) && BCurrentPosY > 0) BCurrentPosY--;
            KillDoubleDropTimer();
        }



        void BlockBomb()
{
 int		x, y, count=0, xx, yy;
 byte[]	BlockBuffer = new byte[100];
 
 
 if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;
 
 CurrentGame.specials_rcvd[8]++;
 
 for (y = 0; y < FIELDHEIGHT; y++)
  for (x = 0; x < FIELDWIDTH; x++)
  if (PlayingFields[MyPosition-1][x][y] == 14)
  {
  
   PlayingFields[MyPosition-1][x][y] = 0;
   
   
   for (yy = y-1; yy <= y+1; yy++)
    for (xx = x-1; xx <= x+1; xx++)
    {
     if (xx == x && yy == y) continue;
     if (xx < 0 || yy < 0 || xx >= FIELDWIDTH || yy >= FIELDHEIGHT) continue;
     BlockBuffer[count] = PlayingFields[MyPosition-1][xx][yy];
     if (BlockBuffer[count] == 14) BlockBuffer[count] = 0;
      else PlayingFields[MyPosition-1][xx][yy] = 0;
      
     count++;
    }
   
   
   for (xx = 0; xx < count; xx++)
    PlayingFields[MyPosition-1][_rand.Next() % FIELDWIDTH][(_rand.Next() % (FIELDHEIGHT-6))+6] = BlockBuffer[xx]; 
  }
  
 while (IsObstructed(BCurrentPosX, BCurrentPosY) && BCurrentPosY > 0) BCurrentPosY--;
 KillDoubleDropTimer();
}
        void Blockquake()
        {
            int x, y, i, amount;

            
            if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;

            CurrentGame.specials_rcvd[7]++;

            for (y = 0; y < FIELDHEIGHT; y++)
            {
                amount = 0;
                i = _rand.Next() % 22;
                if (i < 1) amount++;
                if (i < 4) amount++;
                if (i < 11) amount++;


                if (amount==0) continue;

                if ((_rand.Next() % 2) == 0)
                {
                   
                    for (x = FIELDWIDTH - 1; x >= amount; x--)
                        PlayingFields[MyPosition - 1][x][y] = PlayingFields[MyPosition - 1][x - amount][y];
                    for (x = 0; x < amount; x++) PlayingFields[MyPosition - 1][x][y] = 0;
                }
                else
                {
                    
                    for (x = 0; x < FIELDWIDTH - amount; x++)
                        PlayingFields[MyPosition - 1][x][y] = PlayingFields[MyPosition - 1][x + amount][y];
                    for (x = FIELDWIDTH - 1; x >= FIELDWIDTH - amount; x--) PlayingFields[MyPosition - 1][x][y] = 0;
                }
            }

            while (IsObstructed(BCurrentPosX, BCurrentPosY) && BCurrentPosY > 0) BCurrentPosY--;
            KillDoubleDropTimer();
        }




        void AddSpecial()
{
 byte	value, special;
 int 		x, y, NormalBlocks=0, BlocksBottom=0;
 
 
 for (y = 0; y < FIELDHEIGHT; y++)
  for (x = 0; x < FIELDWIDTH; x++) 
  if (PlayingFields[MyPosition-1][x][y] > 0 
      && PlayingFields[MyPosition-1][x][y] < 6) NormalBlocks++;
           
 
 for (x = 0; x < FIELDWIDTH; x++) 
  if (PlayingFields[MyPosition-1][x][FIELDHEIGHT-1] > 0 ) BlocksBottom++;

 if (0!=NormalBlocks && BlocksBottom >= FIELDWIDTH-1) return;
           
 
 value = (byte)(_rand.Next() % 100);
 for (special = 0; special < 9; special++) if (value < GameData.SFreq[special]) break;
 
 CurrentGame.specials_spawned[special]++;
          
 
 if (0==NormalBlocks)
 {
  do 
  {
   x = (byte)(_rand.Next() % FIELDWIDTH);
  } while (PlayingFields[MyPosition-1][x][FIELDHEIGHT-1] != 0);
  PlayingFields[MyPosition-1][x][FIELDHEIGHT-1] = (byte)(special + 6);
  
  return;
 }
 
 
 do
 {
  x = (byte)(_rand.Next() % FIELDWIDTH);
  y = (byte)(_rand.Next() % FIELDHEIGHT);
 } while (PlayingFields[MyPosition-1][x][y] == 0 || PlayingFields[MyPosition-1][x][y] > 5);


 PlayingFields[MyPosition - 1][x][y] = (byte)(special + 6);
}



        void InsertSpecial(byte spec)
{
 byte	value;
 int		i;
 
 if (strlen(SpecialBuffer) == GameData.SpecialCap) return;
 
 CurrentGame.specials_collected[(int)spec]++;

 if (strlen(SpecialBuffer) == 0) value = 0;
 else
     value = (byte)(_rand.Next() % strlen(SpecialBuffer));

 for (i = SPECIAL_BUFFER_LENGTH; i > value; i--) SpecialBuffer[i] = SpecialBuffer[i-1];
 
 SpecialBuffer[value] = (byte)(spec+1);
 
 Ui.DrawSpecials();
}



        byte RemoveSpecial()
        {
            byte buf = SpecialBuffer[0];
            int i;

            for (i = 0; i < strlen(SpecialBuffer); i++) SpecialBuffer[i] = SpecialBuffer[i + 1];

            Ui.DrawSpecials();

            return buf;
        }



        void UseSpecial(char number)
{
 byte	buf;
 char[]	Buffer= new char[100];
 
 if (!PlayerPlaying[number-1] || !PlayerPlaying[MyPosition-1] 
     || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;
 
 buf = RemoveSpecial();
 if (buf == 0) return;
 
 CurrentGame.specials_used[(int)buf-1]++;

 netcode.Instance.SendSpecial(number, BlockValue[buf + 5], (char)MyPosition);

}



        void CheckCompleteLines(byte JustRemove)
{
 byte	x, i, Line, LineCount=0, BlockCount=0; 
char[]	Buffer= new char[100];
 char[]	SpBuffer= new char[9];
            
 for (Line = 0; Line < FIELDHEIGHT; Line++)
 {
  for (x = 0; x < FIELDWIDTH; x++) if (PlayingFields[MyPosition-1][x][Line] != 0) BlockCount++;
  
  if (BlockCount == FIELDWIDTH) 
  {
   
   for (i = 0; i < FIELDWIDTH; i++) if (PlayingFields[MyPosition-1][i][Line] > 5) 
                                        SpBuffer[PlayingFields[MyPosition-1][i][Line]-6]++;
   
   LineCount++;
   ShiftDownField(Line);
  }
  
  BlockCount = 0;
 }
 

 if (0==LineCount) return;
 
 
 if (0!=JustRemove) return;
 
 
 TotalLines += LineCount;
 CurrentGame.NumberLines =  (uint)TotalLines;

 if ((TotalLines / GameData.LinesForLevel) * GameData.LevelAmount + GameData.StartLevel > PlayerLevels[MyPosition-1])
 {
  PlayerLevels[MyPosition-1] = (TotalLines / GameData.LinesForLevel) * GameData.LevelAmount + GameData.StartLevel;
  Buffer = string.Format("lvl {0} {1}", MyPosition, PlayerLevels[MyPosition-1]).ToCharArray();
  netcode.Instance.SendSocket(Buffer);
 }
 
 
 if (LineCount == 4 && GameData.Classic != 0) 
 {
  Buffer = string.Format("sb 0 cs4 {0}", MyPosition).ToCharArray();
  netcode.Instance.SendSocket(Buffer);
  EventNumber++;
  Buffer = string.Format("{0}.\x02\x13 4 Lines Added to all\x02", EventNumber).ToCharArray();
  netcode.Instance.AddPlayerFormat(Buffer, 0, MyPosition, 1);
  Buffer = string.Format("{0}\n", Buffer).ToCharArray();
  Ui.PrintEventMessage(Buffer);
  CurrentGame.NumberTetris++;
  CurrentGame.LinesAdded += 4;
 }
 
 if (LineCount == 3 && GameData.Classic != 0) 
 {
     Buffer = string.Format("sb 0 cs2 {0}", MyPosition).ToCharArray();
     netcode.Instance.SendSocket(Buffer);
  EventNumber++;
  Buffer = string.Format("{0}.\x02\x13 2 Lines Added to all\x02", EventNumber).ToCharArray();
  netcode.Instance.AddPlayerFormat(Buffer, 0, MyPosition, 1);
  Buffer = string.Format("{0}\n", Buffer).ToCharArray();
  Ui.PrintEventMessage(Buffer);
  CurrentGame.LinesAdded += 2;
 }
 
 if (LineCount == 2 && GameData.Classic !=0) 
 {
  Buffer = string.Format("sb 0 cs1 {0}", MyPosition).ToCharArray();
  netcode.Instance.SendSocket(Buffer);
  EventNumber++;
  Buffer = string.Format("{0}.\x02\x13 1 Line Added to all\x02", MyPosition).ToCharArray();
  netcode.Instance.AddPlayerFormat(Buffer, 0, MyPosition, 1);
  Buffer = string.Format("{0}\n", Buffer).ToCharArray();
  Ui.PrintEventMessage(Buffer);
  CurrentGame.LinesAdded++;
 }
 

 for (Line = 0; Line < 9; Line++)
  for (x = 0; x < LineCount; x++) 
   for (i = 0; i < SpBuffer[Line]; i++) InsertSpecial(Line); 
 
 
 if ((TotalLines / GameData.LinesForSpecial) * GameData.SpecialMult > SpecialsAdded)
 {
  for (i = (byte)((TotalLines / GameData.LinesForSpecial) * GameData.SpecialMult - SpecialsAdded); i > 0; i--) AddSpecial();
  SpecialsAdded = (uint)((TotalLines / GameData.LinesForSpecial) * GameData.SpecialMult);
 }
}
        void Gravity()
        {
            int x, y, i;

            /* already dead or only spectating? */
            if (!PlayerPlaying[MyPosition - 1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;

            CurrentGame.specials_rcvd[6]++;

            for (y = 0; y < FIELDHEIGHT; y++)
                for (x = 0; x < FIELDWIDTH; x++)
                    if (PlayingFields[MyPosition - 1][x][y] == 0)
                    {
                        for (i = y; i > 0; i--) PlayingFields[MyPosition - 1][x][i] = PlayingFields[MyPosition - 1][x][i - 1];
                        PlayingFields[MyPosition - 1][x][0] = 0;
                    }

            /* remove but do not count complete lines */
            CheckCompleteLines(1);
        }





        void DoNewDrop()
{
 byte	value, i;
 char[]		Buffer = new char[100];
 
 
 /* already dead or only spectating? */
 if (!PlayerPlaying[MyPosition-1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return;
 
 /* next block already calculated? */
 if (BNext != -1) BCurrent = BNext; else 
 {
  /* no, so calculate block instead of copying from BNext */
  value = (byte)(_rand.Next() % 100);
  //value = (unsigned char) (100.0 * rand()/(RAND_MAX+1.0)); /* Better rectangular distribution -> bugged */
  for (i = 0; i < 7; i++) if (value < GameData.BFreq[i]) {BCurrent = i; break;}
  
  /* we also need an initial orientation */
  NextBlockOrientation = (int)(_rand.Next() % 4);
  //NextBlockOrientation = (unsigned char) (4.0 * rand()/(RAND_MAX+1.0)); /* Better rectangular distribution -> bugged */
 }
 
 /* calculate BNext */
 value = (byte)(_rand.Next() % 100);
 //value = (unsigned char) (100.0 * rand()/(RAND_MAX+1.0)); /* Better rectangular distribution -> bugged*/
 for (i = 0; i < 7; i++) if (value < GameData.BFreq[i]) {BNext = i; break;}
 
 BlockOrientation = NextBlockOrientation;
 NextBlockOrientation = (int)(_rand.Next() % 4);
 BCurrentPosX = 4;
 BCurrentPosY = 0;
 
 /* dead with this block? */
 if (IsObstructed(BCurrentPosX, BCurrentPosY))
 {
  BCurrent = -1;
  SecondsPlayed = (long)DateTime.Now.Ticks - SecondsPlayed;
  if (SecondsPlayed == 0) SecondsPlayed++;
  FillFieldRandom(MyPosition-1);
  netcode.Instance.SendField(MyPosition-1);
  PlayerPlaying[MyPosition-1] = false;
  Buffer = string.Format("playerlost {0}", MyPosition).ToCharArray();
  netcode.Instance.SendSocket(Buffer);
  Ui.DrawFields((byte)(MyPosition-1));
  Ui.DrawNextBlock();
  
  return;
 }
 
 DroppedBlocks++;
 CurrentGame.NumberBlocks++;
 CurrentGame.Blocks[BCurrent]++;
 
 /* game paused? Don't set timer */
 if (paused) return;

 if (ActiveLevel <= 100)
     SetDropTimer();
 else
     SendMessage();//SendMessage(hGame, WM_TIMER, DROPTIMER, 0);
 
 Ui.DrawFields((byte)(MyPosition-1));
 Ui.DrawNextBlock();
}

        private void SetDropTimer()
        {
            //SetDropTimerSetTimer(hGame, DROPTIMER, ActiveLevel <= 100 ? 1005 - ActiveLevel * 10 : 5, NULL); 
        }

        private void SendMessage()
        {
            //SendMessage(hGame, WM_TIMER, DROPTIMER, 0);
        }

        bool DropBlock()
{
 /* already dead or only spectating? */
 if (!PlayerPlaying[MyPosition-1] || protocol == PROT_TSPEC || protocol == PROT_PLAYREC) return false;
	
 if (IsOutOfField(BCurrentPosX, BCurrentPosY+1) || IsObstructed(BCurrentPosX, BCurrentPosY+1))
 {
  /* Make block permanent */
  SetBlock();
  
  BCurrent  = -1;
  KeyDownPressed = 0;
  
  /* Check for complete lines */
  CheckCompleteLines(0);
  
  /* send changed field */
  netcode.Instance.SendField(MyPosition-1);
  
  Ui.DrawFields((byte)(MyPosition-1));
  Ui.DrawLinesnLevel();
  
  if (protocol == PROT_TETRINET)
      SetDropTimer();//SetTimer(hGame, DROPDELAYTIMER, GameData.Delay, NULL);
    else 
      SetDropTimer();//SetTimer(hGame, DROPDELAYTIMER, 0, NULL);
   
  return true;
 } else
 {
  BCurrentPosY++;
  if (ActiveLevel <= 100)
   SetDropTimer();//SetTimer(hGame, DROPTIMER, ActiveLevel<=100?1005-ActiveLevel*10:5, NULL);
  else
   SetDropTimer();//SendMessage(hGame, WM_TIMER, DROPTIMER, 0);
 }
 
 return false;
}

void LeftBlock()
{
 if (!IsOutOfField(BCurrentPosX-1, BCurrentPosY) && !IsObstructed(BCurrentPosX-1, BCurrentPosY))
    BCurrentPosX--; Ui.DrawFields((byte)(MyPosition-1));
}

void RightBlock()
{
 if (!IsOutOfField(BCurrentPosX+1, BCurrentPosY) && !IsObstructed(BCurrentPosX+1, BCurrentPosY))
 BCurrentPosX++; Ui.DrawFields((byte)(MyPosition-1));
}

/* tries to rotate the block - rot=1: left rot=0: right */
void RotateBlock(byte rot)
{
 int  i;
 short[] shifts = new short[4]{1, -1, 2, -2};
 int  OldOri = BlockOrientation;
 
 if (rot == 0) BlockOrientation--; else BlockOrientation++;
 if (BlockOrientation > 3) BlockOrientation = 0; else
 if (BlockOrientation < 0) BlockOrientation = 3;
 
 /* Already valid orientation? No actions to be taken */
 if (!IsOutOfField(BCurrentPosX, BCurrentPosY) && !IsObstructed(BCurrentPosX, BCurrentPosY)) return;
 
 /* Obstructed by blocks? Not rotating */
 if (IsObstructed(BCurrentPosX, BCurrentPosY))
 {
  BlockOrientation = OldOri;
  return;
 }
 
 /* shift to valid position */
 for (i = 0; i < 4; i++) 
 if (!IsOutOfField(BCurrentPosX+shifts[i], BCurrentPosY) && !IsObstructed(BCurrentPosX+shifts[i], BCurrentPosY)) 
  {BCurrentPosX+=shifts[i]; return;}
  
 /* New Orientation not valid */
 BlockOrientation = OldOri;
}

public static int strlen(byte[] str)
{
    return Encoding.UTF8.GetString(str, 0, str.Length).Length;
}
public static int strlen(char[] str)
{
    return str.ToString().Length;
}
    }
}
